#include "Errorlogdialog.h"
#include "resources.h"
#include "../Logger.h"
#include "../util.h"

#include <QPushButton>
#include <QHeaderView>
#include <QtGlobal>

#include <boost/lexical_cast.hpp>

namespace ui {

ErrorLogDialog::ErrorLogDialog(QWidget *_parent): BaseUI(), filtered(false) {
    parent = _parent;
}

bool ErrorLogDialog::setup() {
    if(!BaseUI::setup(UI_ERROR_LOG_DIALOG))
        return false;

    formWidget->setWindowFlags(Qt::Dialog);
    lstErr = formWidget->findChild<QTableWidget*>("lstErrorLog");
    txtFilter = formWidget->findChild<QLineEdit*>("txtFilter");

    txtFilter->setFocus();

    QPushButton *btnClear = formWidget->findChild<QPushButton*>("btnClear");
    QPushButton *btnApply = formWidget->findChild<QPushButton*>("btnApplyFilter");
    QPushButton *btnReset = formWidget->findChild<QPushButton*>("btnResetFilter");

    QObject::connect(btnClear, SIGNAL(clicked()), this, SLOT(onClear()));
    QObject::connect(btnApply, SIGNAL(clicked()), this, SLOT(onApplyFilter()));
    QObject::connect(btnReset, SIGNAL(clicked()), this, SLOT(onResetFilter()));

#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
    lstErr->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
#else
    lstErr->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
#endif

    return true;
}

void ErrorLogDialog::update(patterns::Observable* /* obs */, void *msg) {
    core::LogEntry *entry = static_cast<core::LogEntry*>(msg);

#ifdef _DEBUG
    std::wcerr << entry->message << std::endl;
#endif

    // on [INIT] message, read all messages in queue
    if(entry->message == L"INIT") {
        const core::LogList& msgs = core::Logger::getInstance().getFullLog();

        for(core::LogList::const_iterator it = msgs.begin();
            it != msgs.end(); ++it) {

            entry = static_cast<core::LogEntry*>((*it).get());

#ifdef _DEBUG
            std::wcerr << entry->message << std::endl;
#endif
            insertItems(entry);
        }
    } else {
        insertItems(entry);
    }
}

void ErrorLogDialog::insertItems(core::LogEntry *entry) {
    QTableWidgetItem *timeItem = NULL, *msgItem = NULL, *senderItem = NULL;
    QColor fgColor;
    std::wstring txt;
    short errType;
    char buffer[80];

    extractParams(entry->message, errType, txt);
    fgColor = getColorForType(errType);
    fmt_time(entry->timestamp, buffer);

    timeItem = new QTableWidgetItem(QString::fromLatin1(buffer));
    msgItem = new QTableWidgetItem(QString::fromStdWString(txt));
    senderItem = new QTableWidgetItem(QString::fromStdWString(entry->sender));

    timeItem->setBackground(fgColor);
    msgItem->setBackground(fgColor);
    senderItem->setBackground(fgColor);

    insertRow(timeItem, msgItem, senderItem);
}

void ErrorLogDialog::insertRow(QTableWidgetItem *time, QTableWidgetItem *msg, QTableWidgetItem *sender) {
    int currentRow = lstErr->rowCount();
    lstErr->insertRow(currentRow);

    if(time != NULL)
        lstErr->setItem(currentRow, 0, time);
    if(msg != NULL)
        lstErr->setItem(currentRow, 2, msg);
    if(sender != NULL)
        lstErr->setItem(currentRow, 1, sender);
}

// add lots of checks
void ErrorLogDialog::extractParams(const std::wstring &msg, short &type, std::wstring &txt) {
    typedef std::wstring::size_type StrPos;

    StrPos firstEq  = msg.find_first_of(L'=');
    StrPos nextLt   = msg.find_first_of(L'>', firstEq);
    std::wstring strType = msg.substr(firstEq + 1, nextLt - firstEq - 1);

    StrPos secondEq = msg.find_first_of(L'=', nextLt);
    StrPos secondLt = msg.find_first_of(L'>', secondEq);

    txt = msg.substr(secondEq + 2, secondLt - secondEq - 3);
    type = boost::lexical_cast<short>(strType);
}

QColor ErrorLogDialog::getColorForType(const short &type) {
    QColor color;

    switch(type) {
    case core::Information:
        color = Qt::green;
        break;
    case core::Debug:
        color = Qt::cyan;
        break;
    case core::Error:
        color = Qt::red;
        break;
    case core::Warning:
        color = Qt::yellow;
        break;
    case core::Alert:
        color = Qt::darkRed;
        break;
    default:
        color = Qt::black;
        break;
    }

    return color;
}

void ErrorLogDialog::onClear() {
    lstErr->clearContents();
    lstErr->setRowCount(0);
}

void ErrorLogDialog::onApplyFilter() {
    QTableWidgetItem *messageItem;
    QString messageText;
    QString filterText = txtFilter->text().toLower();

    if(filtered) {
        onResetFilter();
    }

    for(int row = 0; row < lstErr->rowCount(); ++row) {
        messageItem = lstErr->item(row, 2);
        messageText = messageItem->text().toLower();

        if(!messageText.contains(filterText)) {
            lstErr->hideRow(row);
        }
    }

    filtered = true;
}

void ErrorLogDialog::onResetFilter() {
    for(int row = 0; row < lstErr->rowCount(); ++row)
        lstErr->showRow(row);

    txtFilter->setText("");

    filtered = false;
}

}
